﻿using System;

namespace Communication.Help;

public static class BitExtensions
{
    private static readonly ushort[] MaskUshort =
    [
        0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000,
        0x4000, 0x8000
    ];


    /// <summary>
    ///     判断ushort类型的value的第bitIndex位是否被设置
    /// </summary>
    /// <param name="value">要判断的原始值</param>
    /// <param name="bitIndex">位索引 (0-15)</param>
    /// <returns></returns>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public static bool IsBitSet(this ushort value, int bitIndex)
    {
        // 如果bitIndex小于0或者大于15，则抛出ArgumentOutOfRangeException异常
        return bitIndex is < 0 or > 15
            ? throw new ArgumentOutOfRangeException(nameof(bitIndex), bitIndex, "位索引必须在 0 到 15 之间")
            // 否则，判断value与MaskUshort[bitIndex]的按位与结果是否不等于0
            : (value & MaskUshort[bitIndex]) != 0;
    }

    /// <summary>
    ///     判断byte类型的value的第bitIndex位是否被设置
    /// </summary>
    /// <param name="value">要判断的原始值</param>
    /// <param name="bitIndex">位索引 (0-7)</param>
    /// <returns></returns>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public static bool IsBitSet(this byte value, int bitIndex)
    {
        // 如果bitIndex小于0或者大于7，抛出ArgumentOutOfRangeException异常
        return bitIndex is < 0 or > 7
            ? throw new ArgumentOutOfRangeException(nameof(bitIndex), bitIndex, "位索引必须在 0 到 7 之间")
            // 否则，判断value的第bitIndex位是否被设置
            : (value & MaskUshort[bitIndex]) != 0;
    }

    /// <summary>
    ///     设置 ushort 值的指定位状态
    /// </summary>
    /// <param name="value">要修改的原始值</param>
    /// <param name="bitIndex">位索引 (0-15)</param>
    /// <param name="setTo">true=置位(1), false=复位(0)</param>
    /// <returns>修改后的 ushort 值</returns>
    /// <exception cref="ArgumentOutOfRangeException">位索引超出范围</exception>
    public static ushort SetBit(this ushort value, int bitIndex, bool setTo)
    {
        // 验证位索引范围 (0-15)
        if (bitIndex is < 0 or > 15)
            throw new ArgumentOutOfRangeException(nameof(bitIndex), bitIndex, "位索引必须在 0 到 15 之间");

        // 获取目标位的掩码
        var mask = MaskUshort[bitIndex];

        return setTo
            ? (ushort)(value | mask) // 置位操作：使用 OR 设置1
            : (ushort)(value & ~mask); // 复位操作：使用 AND 取反掩码设置0
    }


    /// <summary>
    ///     设置 byte 值的指定位状态
    /// </summary>
    /// <param name="value">要修改的原始值</param>
    /// <param name="bitIndex">位索引 (0-7)</param>
    /// <param name="setTo">true=置位(1), false=复位(0)</param>
    /// <returns>修改后的 ushort 值</returns>
    /// <exception cref="ArgumentOutOfRangeException">位索引超出范围</exception>
    public static ushort SetBit(this byte value, int bitIndex, bool setTo)
    {
        // 验证位索引范围 (0-7)
        if (bitIndex is < 0 or > 7)
            throw new ArgumentOutOfRangeException(nameof(bitIndex), bitIndex, "位索引必须在 0 到 7 之间");

        // 获取目标位的掩码
        var mask = MaskUshort[bitIndex];

        return setTo
            ? (ushort)(value | mask) // 置位操作：使用 OR 设置1
            : (ushort)(value & ~mask); // 复位操作：使用 AND 取反掩码设置0
    }
}